#include <ctime>

#include <iostream>
#include "net_common.h"
#include "network_message_handler.h"
#include "heart_beat.pb.h"
#include "left_button_clicked.pb.h"
#include "user_login.pb.h"
#include "user_register.pb.h"
#include "game_init.pb.h"
#include "game_over.pb.h"
#include "user_start_matching.pb.h"
#include "user_stop_matching.pb.h"

#include "user_login_widget.h"
#include "user_register_widget.h"

#include "user.h"

// #include "gameresultdialog.h"

std::string time_stamp_to_string(std::time_t time_stamp) {
    // 将 time_t 转换为 tm 结构（本地时间）
    std::tm* local_time = std::localtime(&time_stamp);

    // 定义缓冲区来存储格式化后的时间字符串
    char buffer[100];

    // 格式化时间为可读的字符串
    std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", local_time);

    // 返回格式化后的字符串
    return std::string(buffer);
}

/**
 * @brief: 处理服务器端发过来的心跳消息
 * @details: 客户端与服务器端建立连接(tcp_client)后，客户端每隔一段时间发送一个心跳消息到服务器端，服务器端接收到心跳消息后，\
 *      回复一个心跳消息到客户端，
 */
int network_message_handler::message_handler_heart_beat(std::shared_ptr<tcp_client> tcp_client, const network_message& msg)
{
    HeartBeatS2CProto heart_beat_from_server;
    bool parse_result = heart_beat_from_server.ParseFromString(msg.data_);
    if (!parse_result) {
        return EC_PROTOBUF_PARSE_FAILED;
    }

    std::cout << "received heart beat msg: " << heart_beat_from_server.DebugString() << std::endl;

    HeartBeatS2CProto heart_beat_to_client;
    heart_beat_to_client.set_timestamp(time(nullptr));
    heart_beat_to_client.set_sequence(heart_beat_from_server.sequence());

    auto send_msg_str = heart_beat_to_client.SerializeAsString();
    network_message send_msg(MSG_TYPE_S2C_HEARTBEAT, send_msg_str);

    return EC_OK;
}

int network_message_handler::message_handler_user_login(
    std::shared_ptr<tcp_client> tcp_client, const network_message& msg)
{
    int ret = EC_OK;
    UserLoginS2CProto userLoginProto;
    bool parse_result = userLoginProto.ParseFromString(msg.data_);
    if (!parse_result) {
        return EC_PROTOBUF_PARSE_FAILED;
    }

    std::cout << "received user login msg: " << userLoginProto.DebugString() << std::endl;

    if (user_login_wgt_.expired()) {
        return EC_WEAK_PTR_EXPIRED;
    }

    auto user_login_wgt_ptr = user_login_wgt_.lock();
    QString response_msg = QString::fromStdString(userLoginProto.error_msg());
    std::cout << "user login result: " << userLoginProto.error_msg() << std::endl;
    user_login_wgt_ptr->onUserLoginResponse(userLoginProto.login_result(), response_msg,
        userLoginProto.uid(), userLoginProto.user_name());

    return ret;
}

int network_message_handler::message_handler_user_register(
    std::shared_ptr<tcp_client> tcp_client, const network_message& msg)
{
    int ret = EC_OK;
    UserRegisterS2CProto userRegisterProto;
    bool parse_result = userRegisterProto.ParseFromString(msg.data_);
    if (!parse_result) {
        return EC_PROTOBUF_PARSE_FAILED;
    }

    std::cout << "received user register msg: " << userRegisterProto.DebugString() << std::endl;

    if (user_register_wgt_.expired()) {
        return EC_WEAK_PTR_EXPIRED;
    }

    auto user_register_wgt_ptr = user_register_wgt_.lock();
    QString response_msg = QString::fromStdString(userRegisterProto.error_msg());

    std::cout << "user register result: " << userRegisterProto.error_msg() << std::endl;
    ret = user_register_wgt_ptr->onUserRegisterResponse(userRegisterProto.register_result(), response_msg);

    return ret;
}

int network_message_handler::message_handler_left_button_clicked(
    std::shared_ptr<tcp_client> tcp_client, const network_message& msg)
{
    int ret = EC_OK;
    LeftButtonClickedS2CProto left_button_clicked_proto;
    bool parse_result = left_button_clicked_proto.ParseFromString(msg.data_);
    if (!parse_result) {
        return EC_PROTOBUF_PARSE_FAILED;
    }

    std::cout << "received left button clicked msg: " << left_button_clicked_proto.DebugString() << std::endl;

    QVector<Position> positions;
    for (auto &pos : left_button_clicked_proto.pos()) {
        positions.push_back(Position(pos.row(), pos.col()));
    }

    if (left_button_clicked_proto.is_bomb()) {
        /* TODO: 校验 */
    }

    if (mine_sweeper_wgt_.expired()) {
        return EC_WEAK_PTR_EXPIRED;
    }
    auto mine_sweeper_wgt_ptr = mine_sweeper_wgt_.lock();
    bool is_opponent = !(left_button_clicked_proto.player_index() == mine_sweeper_wgt_ptr->playerIndex());
    mine_sweeper_wgt_ptr->onRemoteLeftButtonClicked(is_opponent, positions);
    return ret;
}

int network_message_handler::message_handler_user_start_matching(
    std::shared_ptr<tcp_client> tcp_client, const network_message& msg)
{
    int ret = EC_OK;
    UserStartMatcingS2CProto user_start_matching_proto;
    bool parse_result = user_start_matching_proto.ParseFromString(msg.data_);
    if (!parse_result) {
        return EC_PROTOBUF_PARSE_FAILED;
    }

    std::cout << "received user start matching msg: " << user_start_matching_proto.DebugString() << std::endl;

    if (user_start_matching_proto.result() == UserStartMatcingFailed) {
        return EC_MATCHING_FAILED;
    } else if (user_start_matching_proto.result() == UserStartMatcingWaitingForPlayer) {
        main_widget_->setIsMatching(true);
        return EC_OK;
    }

    if (mine_sweeper_wgt_.expired()) {
        return EC_WEAK_PTR_EXPIRED;
    }
    auto mine_sweeper_wgt_ptr = mine_sweeper_wgt_.lock();
    auto &user = User::getInstance();

    if (user.uid() == user_start_matching_proto.uid1()) {
        mine_sweeper_wgt_ptr->setPlayerIndex(PlayerIndex1);
    } else if (user.uid() == user_start_matching_proto.uid2()) {
        mine_sweeper_wgt_ptr->setPlayerIndex(PlayerIndex2);
    } else {
        return EC_E_INVALID_PARAM;
    }
    return ret;
}

int network_message_handler::message_handler_user_stop_matching(
    std::shared_ptr<tcp_client> tcp_client, const network_message& msg)
{
    int ret = EC_OK;
    UserStopMatcingS2CProto user_stop_matching_proto;
    bool parse_result = user_stop_matching_proto.ParseFromString(msg.data_);
    if (!parse_result) {
        return EC_PROTOBUF_PARSE_FAILED;
    }

    std::cout << "received user stop matching msg: " << user_stop_matching_proto.DebugString() << std::endl;

    if (user_stop_matching_proto.result() != UserStopMatcingSuccess) {
        return EC_MATCHING_FAILED;
    }

    main_widget_->setIsMatching(false);

    return ret;
}

int network_message_handler::message_handler_game_init(
    std::shared_ptr<tcp_client> tcp_client, const network_message& msg)
{
    int ret = EC_OK;
    GameInitS2CProto gameInitProto;
    bool parse_result = gameInitProto.ParseFromString(msg.data_);
    if (!parse_result) {
        return EC_PROTOBUF_PARSE_FAILED;
    }

    std::cout << "received game init msg: " << gameInitProto.DebugString() << std::endl;

    QVector<Position> bombsPostions;
    for (auto &pos : gameInitProto.bombs()) {
        bombsPostions.push_back(Position(pos.row(), pos.col()));
    }

    QVector<Position> openedPositions;
    for (auto &pos : gameInitProto.positions()) {
        openedPositions.push_back(Position(pos.row(), pos.col()));
    }

    if (mine_sweeper_wgt_.expired()) {
        return EC_WEAK_PTR_EXPIRED;
    }

    auto mine_sweeper_wgt_ptr = mine_sweeper_wgt_.lock();
    if (mine_sweeper_wgt_ptr == nullptr) {
        std::cout << "mine_sweeper_wgt_ptr is nullptr" << std::endl;
        return EC_E_NULL_PTR;
    }
    mine_sweeper_wgt_ptr->onInitGame(gameInitProto.playerindex(), bombsPostions, openedPositions);

    main_widget_->hideWindow();
    game_widget_->showWindow();
    return ret;
}

int network_message_handler::message_handler_game_over(
    std::shared_ptr<tcp_client> tcp_client, const network_message& msg)
{
    int ret = EC_OK;
    GameOverS2CProto gameOverProto;
    bool parse_result = gameOverProto.ParseFromString(msg.data_);
    if (!parse_result) {
        return EC_PROTOBUF_PARSE_FAILED;
    }

    std::cout << "receive a game over msg from client: " << gameOverProto.DebugString() << std::endl;

    /* 停止计时器 */

    /* reset 界面 */

    // auto mine_sweeper_wgt_ptr = mine_sweeper_wgt_.lock();
    // mine_sweeper_wgt_ptr->reset();

    game_widget_->showGameResultDiag();

    return ret;
}

/* 在此处添加消息类型和消息处理方式的映射关系 */
void network_message_handler::init_message_handler_map()
{
    register_message_handler(MSG_TYPE_S2C_HEARTBEAT, &network_message_handler::message_handler_heart_beat);
    register_message_handler(MSG_TYPE_S2C_USER_LOGIN, &network_message_handler::message_handler_user_login);
    register_message_handler(MSG_TYPE_S2C_USER_REGISTER, &network_message_handler::message_handler_user_register);
    register_message_handler(MSG_TYPE_S2C_LEFT_BUTTON_CLICKED,
        &network_message_handler::message_handler_left_button_clicked);
    register_message_handler(MSG_TYPE_S2C_START_MATCHING,
            &network_message_handler::message_handler_user_start_matching);
    register_message_handler(MSG_TYPE_S2C_STOP_MATCHING,
                &network_message_handler::message_handler_user_stop_matching);
    register_message_handler(MSG_TYPE_S2C_GAME_INIT, &network_message_handler::message_handler_game_init);
    register_message_handler(MSG_TYPE_S2C_GAME_OVER, &network_message_handler::message_handler_game_over);
}

int network_message_handler::handle_message(std::shared_ptr<tcp_client> tcp_client, const network_message& msg)
{
    int ret;

    /* 校验check sum */
    if (msg.header_.checksum_ != msg.caculate_checksum()) {
        std::cout << "checksum error, msg type: " << msg.header_.msg_type_ << std::endl;
        return EC_E_CHECKSUM_ERROR;
    }

    auto it = msg_handler_map_.find(msg.header_.msg_type_);
    if (it == msg_handler_map_.end()) {
        std::cout << "unsupported msg type: " << msg.header_.msg_type_ << std::endl;
        return EC_E_INVALID_PARAM;
    }

    auto func = it->second;
    if (func == nullptr) {
        return EC_E_NULL_PTR;
    }
    
    ret = func(this, tcp_client, msg);
    if (ret != EC_OK) {
        return ret;
    }

    return EC_OK;
}
